package chalmers.game.subterranean.model.player;

import chalmers.game.subterranean.event.Bus;
import chalmers.game.subterranean.event.events.player.JumpEvent;
import chalmers.game.subterranean.model.physics.IMovableBody;
import chalmers.game.subterranean.util.Direction;
import chalmers.game.subterranean.util.options.Speeds;
import lombok.Setter;

/**
 * Regulates the player while clinging to a wall.
 * 
 * @author Alex Evert
 */
public class StateWall implements IState {

  private @Setter
  PlayerContext player;
  private @Setter
  Direction clingDirection;
  private @Setter
  int timeOnWall;

  /**
   * Jump away from the wall.
   * 
   * @param body
   */
  @Override
  public void jump(IMovableBody body) {
    int speedSign;
    Direction lookDir;
    if (clingDirection.equals(Direction.EAST)) {
      speedSign = -1;
      lookDir = Direction.WEST;
    } else {
      speedSign = 1;
      lookDir = Direction.EAST;
    }
    body.setXVelocity(speedSign * Speeds.RUNSPEED);
    body.setYVelocity(Speeds.JUMPSPEED);
    player.setStateAir();
    player.look(lookDir);
    Bus.INSTANCE.post(new JumpEvent());
  }

  /**
   * If player tries to run away from wall she goes to the airstate.
   * 
   * @param body
   * @param direction
   */
  @Override
  public void run(IMovableBody body, Direction direction) {
    if (!direction.equals(clingDirection)) {
      body.setXVelocity(0);
      player.setStateAir();
    }
  }

  @Override
  public void stop(IMovableBody body) {

  }

  /**
   * Either fall or land.
   */
  @Override
  public void bounce(IMovableBody body, Direction direction) {
    if (direction == Direction.SOUTH) {
      // Hit the floor. Stop and change to groundstate.
      body.setYVelocity(0);
      player.setStateGround();
    } else if (direction == Direction.NORTH) {
      // Hit the ceiling. Loose grip of wall.
      body.setYVelocity(0);
      player.setStateAir();
    }
  }

  /**
   * If the player will change square we fall. TODO: Fix when to fall...
   * 
   * @param body the body whose surrounding should be checked.
   */
  @Override
  public void checkSurrounding(IMovableBody body) {
    if (timeOnWall > 0) {
      timeOnWall--;
      // If there's nothing to cling to we go to the air state.
      if (body.findFreeSpace(clingDirection)) {
        body.setGravityfactor(1);
        player.setStateAir();
      }
    } else {
      // After the cling time is up we fall.
      body.setXVelocity(0);
      player.setStateAir();
    }
  }
}
